package com.xiaoyu.lanling.feature.videomatch.activity

import `in`.srain.cube.app.lifecycle.AppActivityLifecycleCallbacks
import android.app.Activity
import android.content.Context
import android.media.MediaPlayer
import android.os.Bundle
import android.os.PowerManager
import android.view.View
import com.xiaoyu.base.app.App
import com.xiaoyu.base.app.AppContext
import com.xiaoyu.base.app.GlobalUI
import com.xiaoyu.base.data.UserData
import com.xiaoyu.base.event.AppEventBus
import com.xiaoyu.base.event.ErrorMessageEvent
import com.xiaoyu.base.event.SimpleEventHandler
import com.xiaoyu.base.utils.extensions.setOnClickDebounceListener
import com.xiaoyu.lanling.R
import com.xiaoyu.lanling.activity.base.AppCompatToolbarActivity
import com.xiaoyu.lanling.activity.base.BaseDialogFragment
import com.xiaoyu.lanling.event.videomatch.*
import com.xiaoyu.lanling.feature.videomatch.data.VideoMatchData
import com.xiaoyu.lanling.feature.videomatch.data.VideoMatchData.Companion.MATCH_STATUS_EXIT
import com.xiaoyu.lanling.feature.videomatch.data.VideoMatchData.Companion.MATCH_STATUS_INIT
import com.xiaoyu.lanling.feature.videomatch.data.VideoMatchData.Companion.MATCH_STATUS_MATCHED
import com.xiaoyu.lanling.feature.videomatch.data.VideoMatchData.Companion.MATCH_STATUS_WAITING
import com.xiaoyu.lanling.feature.videomatch.log.VideoMatchLogger
import com.xiaoyu.lanling.feature.videomatch.util.VideoMatchNotificationUtils
import com.xiaoyu.lanling.feature.voicematch.data.VoiceMatchData
import com.xiaoyu.lanling.lifecycle.disposeOn
import com.xiaoyu.lanling.media.image.ImageViewUtil
import com.xiaoyu.lanling.router.Router
import com.xiaoyu.lib_av.datamodel.CallParams
import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable
import kotlinx.android.synthetic.main.video_match_waiting_activity.*
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import java.util.concurrent.TimeUnit

class VideoMatchWaitingActivity : AppCompatToolbarActivity(), BaseDialogFragment.OnDismissListener {

    companion object {
        const val subtitleCount = 3
        var isShowing = false
        val maleSubtitleMap = mutableMapOf<Int, Int>().apply {
            put(0, R.string.voice_match_waiting_male_subtitle_0)
            put(1, R.string.voice_match_waiting_male_subtitle_1)
            put(2, R.string.voice_match_waiting_male_subtitle_2)
        }
        val femaleSubtitleMap = mutableMapOf<Int, Int>().apply {
            put(0, R.string.voice_match_waiting_female_subtitle_0)
            put(1, R.string.voice_match_waiting_female_subtitle_1)
            put(2, R.string.voice_match_waiting_female_subtitle_2)
        }
    }

    private val requestTag = Any()
    private var mSubtitleIndex: Int = 0
    private var mMainTaskTopActivity: Activity? = null
    private var matchStartDelayPassed = false
    private var matchAppliedStartTime = 0L

    private var mRingtoneMediaPlayer: MediaPlayer? = null
    private var mWaitStartTime = 0L
    private var mMatchStatus = MATCH_STATUS_INIT
    private var mIsInQueueDisposable: Disposable? = null
    private var mRankDisposable: Disposable? = null

    override fun onCreateSafelyAfterAppFinishInit(savedInstanceState: Bundle?) {
        super.onCreateSafelyAfterAppFinishInit(savedInstanceState)
        setContentView(R.layout.video_match_waiting_activity)
        setDarkStatusBar()

        initBind()
        initEvent()
        initData()
    }

    override fun onResumeSafelyAfterAppFinishInit(isFirstTimeResume: Boolean) {
        super.onResumeSafelyAfterAppFinishInit(isFirstTimeResume)
        mMainTaskTopActivity = App.getInstance().topActivity
        playRingtone()
    }

    override fun onPause() {
        super.onPause()
        closeRingtone()
    }

    override fun onDestroy() {
        super.onDestroy()
        dispose()
        logEventForExitBeforeMatch()
        isShowing = false
    }

    override fun onBackPressed() {
    }

    private fun logEventForExitBeforeMatch() {
        when (mMatchStatus) {
            VoiceMatchData.MATCH_STATUS_INIT -> VideoMatchLogger.logVideoMatchExitBeforeMatch()
            VoiceMatchData.MATCH_STATUS_WAITING -> exit("kill_app")
        }
    }

    private fun initBind() {
        back.setOnClickDebounceListener {
            back.isEnabled = false
            exit("back")
            VideoMatchData.exitMatch(requestTag)
        }
    }

    private fun exit(reason: String) {
        logEventForExitRequestStart(reason)
        VideoMatchData.exitMatch(requestTag)
    }

    private fun logEventForExitRequestStart(reason: String) {
        val waitTime = (if (mWaitStartTime == 0L) 0L else System.currentTimeMillis() - mWaitStartTime).div(1000)
        VideoMatchLogger.logVideoMatchExitStart(waitTime, reason)
    }

    private fun initEvent() {
        AppEventBus.bindContainerAndHandler(this, object : SimpleEventHandler() {
            @Subscribe(threadMode = ThreadMode.MAIN)
            fun onEvent(event: VideoMatchExitMatchEvent) {
                if (event.isNotFromThisRequestTag(requestTag)) {
                    return
                }
                if (event.isFailed) {
                    VideoMatchLogger.logVideoMatchExitFailed()
                } else {
                    mMatchStatus = MATCH_STATUS_EXIT
                    VideoMatchLogger.logVideoMatchExitSuccess()
                    finishAndRemoveTask()
                }
            }

            @Subscribe(threadMode = ThreadMode.MAIN)
            fun onEvent(event: VideoMatchReceiveEvent) {
                processCall(event.callParams)
                finishAndRemoveTask()
            }

            @Subscribe(threadMode = ThreadMode.MAIN)
            fun onEvent(event: VideoMatchIsInQueueEvent) {
                if (event.isNotFromThisRequestTag(requestTag)) {
                    return
                }
                if (event.isInQueue) {
                    return
                }
                finishAndRemoveTask()
            }

            @Subscribe(threadMode = ThreadMode.MAIN)
            fun onEvent(event: ErrorMessageEvent) {
                if (event.isNotFromThisRequestTag(requestTag)) {
                    return
                }
                back.isEnabled = true
            }

            @Subscribe(threadMode = ThreadMode.MAIN)
            fun onEvent(event: VideoMatchApplyMatchEvent) {
                if (event.isNotFromThisRequestTag(requestTag)) {
                    return
                }
                if (event.isFailed) {
                    dispose()
                    return
                }
                matchAppliedStartTime = System.currentTimeMillis()
                if (event.callParams.isInvalid) {
                    mWaitStartTime = System.currentTimeMillis()
                    mMatchStatus = MATCH_STATUS_WAITING
                    waitingMatch()
                } else {
                    mMatchStatus = MATCH_STATUS_MATCHED
                    finishAndRemoveTask()
                    Router.instance.gotoVideoMatchCallActivity(this@VideoMatchWaitingActivity, event.callParams, true)
                }
            }

            @Subscribe(threadMode = ThreadMode.MAIN)
            fun onEvent(event: VideoMatchCurrentRankEvent) {
                if (event.isNotFromThisRequestTag(requestTag)) {
                    return
                }
                rank_desc.text = getString(R.string.video_match_waiting_rank_desc, event.result.toString())
                rank_desc.visibility = View.VISIBLE
            }
        })
    }

    private fun dispose() {
        mRankDisposable?.dispose()
        mIsInQueueDisposable?.dispose()
    }

    private fun initData() {
        isShowing = true
        ImageViewUtil.loadAvatarRoundWithBoard(avatar, UserData.getInstance().user, 96, 2, R.color.user_info_avatar_border, false)
        Observable.timer(1, TimeUnit.SECONDS)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe {
                    matchStartDelayPassed = true
                    VideoMatchLogger.logVideoMatchStart()
                    VideoMatchData.applyMatch(requestTag)
                }
                .disposeOn(this)
        Observable.interval(0, 3, TimeUnit.SECONDS)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe {
                    mSubtitleIndex = (mSubtitleIndex + 1) % subtitleCount
                    val subtitleRes = if (UserData.getInstance().user.isMale) maleSubtitleMap[mSubtitleIndex] else femaleSubtitleMap[mSubtitleIndex]
                    subtitleRes?.let {
                        subtitle.setText(subtitleRes)
                    }
                }
                .disposeOn(this)
    }

    private fun waitingMatch() {
        checkIsInQueue()
        startQuitTimer()
        startRankTimer()
    }

    private fun checkIsInQueue() {
        mIsInQueueDisposable = Observable.interval(30, 30, TimeUnit.SECONDS)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe {
                    VideoMatchData.isInQueue(requestTag)
                }
    }

    private fun startQuitTimer() {
        Observable.timer(5, TimeUnit.MINUTES)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe {
                    exit("timeout")
                    GlobalUI.getInstance().showToast(R.string.voice_match_waiting_timeout_toast)
                }
                .disposeOn(this)
    }

    private fun startRankTimer() {
        mRankDisposable = Observable.interval(0, 5, TimeUnit.SECONDS)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe {
                    VideoMatchData.currentRank(requestTag)
                }
    }

    private fun processCall(params: CallParams) {
        val powerManager = AppContext.getContext().getSystemService(Context.POWER_SERVICE) as PowerManager
        if (powerManager.isInteractive && AppActivityLifecycleCallbacks.getInstance().isAppInForeground) {
            Router.instance.gotoVideoMatchCallActivity(this, params, false)
        } else {
            VideoMatchNotificationUtils.instance.showVideoMatchNotification(params, isCaller = false, isReceive = true)
        }
    }

    private fun playRingtone() {
        if (mRingtoneMediaPlayer != null && mRingtoneMediaPlayer?.isPlaying == true) {
            return
        }
        try {
            mRingtoneMediaPlayer = MediaPlayer.create(AppContext.getContext(), R.raw.voice_match_waiting_raw)
            mRingtoneMediaPlayer?.isLooping = true
            mRingtoneMediaPlayer?.start()
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    private fun closeRingtone() {
        mRingtoneMediaPlayer?.pause()
        mRingtoneMediaPlayer?.stop()
        mRingtoneMediaPlayer?.reset()
        mRingtoneMediaPlayer?.release()
        mRingtoneMediaPlayer?.setOnPreparedListener(null)
        mRingtoneMediaPlayer = null
    }

    private fun logMatchExit() {
        if (matchStartDelayPassed.not()) {
            VideoMatchLogger.logVideoMatchExitBeforeMatch()
        } else {
            VideoMatchLogger.logVideoMatchExitStart(System.currentTimeMillis() - matchAppliedStartTime / 1000, "back")
        }
    }

    override fun onDismiss() {
        finishAndRemoveTask()
    }
}